﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace AllDemo
{
    public partial class 绘制两个圆的内公切点 : Form
    {
        public 绘制两个圆的内公切点()
        {
            InitializeComponent();
            MouseDown += new MouseEventHandler(OnMouseDown);
            this.DoubleBuffered = true;    //开启二次缓存
            centerOfCircle1.X = 200;
            centerOfCircle1.Y = 400;
            centerOfCircle2.X = 400;
            centerOfCircle2.Y = 200;
            pointOfRotation.X = 300;
            pointOfRotation.Y = 300;
        }


        private PointF centerOfCircle1 = new Point();   //圆心
        private PointF centerOfCircle2 = new Point();   //圆心
        private PointF pointOfRotation = new Point();   //旋转点
        private float rotationAngle = (float)(1 * Math.PI / 180);       //旋转角度
        private int r1 = 90;                           //半径
        private int r2 = 50;
    
        Graphics g;
        private void drawCircle()
        {
            g.SmoothingMode = SmoothingMode.HighQuality;  //图片柔顺模式选择
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;//高质量
            g.CompositingQuality = CompositingQuality.HighQuality;//再加一点
            g.FillEllipse(new SolidBrush(Color.Orange), centerOfCircle1.X - r1, centerOfCircle1.Y - r1, 2 * r1, 2 * r1);
            g.FillEllipse(new SolidBrush(Color.Green), centerOfCircle2.X - r2, centerOfCircle2.Y - r2, 2 * r2, 2 * r2);
            getTangentPoint(centerOfCircle1.X, centerOfCircle1.Y, r1, centerOfCircle2.X, centerOfCircle2.Y, r2);
            g.DrawLine(Pens.Black, r1_up_point, r2_low_point);
            g.DrawLine(Pens.Black, r1_low_point, r2_up_point);

            g.DrawLine(Pens.Red, pointOfRotation.X - 5, pointOfRotation.Y, pointOfRotation.X + 5, pointOfRotation.Y);
            g.DrawLine(Pens.Red, pointOfRotation.X , pointOfRotation.Y-5, pointOfRotation.X , pointOfRotation.Y+5);
            Pen pen = new Pen(Color.Gold, 2);

        }
        
        /// <summary>
        /// 计算两个相离的圆的内公切线。（相交没有内公切线，只有外公切线）
        /// 圆C1, 圆心(a, b), 半径r1.
        /// 圆C2, 圆心(c, d), 半径r2.
        /// </summary>
        /// <returns>返回两条内公切线段，线段的两个端点是圆上的切点。</returns>
        PointF r2_low_point = new PointF();
        PointF r2_up_point = new PointF();
        PointF r1_up_point = new PointF();
        PointF r1_low_point = new PointF();
        public void getTangentPoint(double a, double b, double r1, double c, double d, double r2)
        {
            double α =Math.Atan2((b - d) , (a - c));    //求中两个圆心连线的斜率角度
            double centerLine;
            if (d == b)                            //处理斜率为零的情况       
            {
                centerLine = a-c;
            }
            else
            {
                centerLine = (d - b) / Math.Sin(α); //求两个圆心连线长度
            }
            double β = Math.Acos((r1 + r2) / centerLine);  //求两个圆心连线和圆心到切点垂线的夹角
            double θ = β - α;                              
            double r2LowX = r2 * Math.Cos(θ);
            double r2LowY = r2 * Math.Sin(θ);
            double r1UpX = r1 * Math.Cos(θ);
            double r1UpY = r1 * Math.Sin(θ);
            r2_low_point.X = centerOfCircle2.X - (float)r2LowX;
            r2_low_point.Y = centerOfCircle2.Y + (float)r2LowY;
            r1_up_point.X = centerOfCircle1.X + (float)r1UpX;
            r1_up_point.Y = centerOfCircle1.Y - (float)r1UpY;
            PointF r2_tempoint= Transition( r2_low_point.X- centerOfCircle2.X,  centerOfCircle2.Y- r2_low_point.Y, 2 * β, 2);
            r2_up_point.X = centerOfCircle2.X + r2_tempoint.X;
            r2_up_point.Y = centerOfCircle2.Y + r2_tempoint.Y;
            PointF r1_tempoint = Transition(r1_up_point.X - centerOfCircle1.X,  centerOfCircle1.Y- r1_up_point.Y, 2 * β, 2);
            r1_low_point.X = centerOfCircle1.X + r1_tempoint.X;
            r1_low_point.Y = centerOfCircle1.Y + r1_tempoint.Y;
        }
        //点绕点旋转
        private PointF Transition(float _x, float _y, double _angle, int fx)
        {
            double newX = 0;
            double newY = 0;
            if (fx == 1)
            {
                newX = _x * Math.Cos(_angle) - _y * Math.Sin(_angle);
                newY = _x * Math.Sin(_angle) + _y * Math.Cos(_angle);
            }
            else
            {
                newX = _x * Math.Cos(_angle) + _y * Math.Sin(_angle);
                newY = _x * Math.Sin(_angle) - _y * Math.Cos(_angle);
            }

            return new PointF((float)newX, (float)newY);
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            g = e.Graphics;
            drawCircle();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            PointF temp1Point = Transition(centerOfCircle1.X - pointOfRotation.X, centerOfCircle1.Y - pointOfRotation.Y, rotationAngle, 1);
            PointF temp2Point = Transition(centerOfCircle2.X - pointOfRotation.X, centerOfCircle2.Y - pointOfRotation.Y, rotationAngle, 1);
            centerOfCircle1.X = pointOfRotation.X + temp1Point.X;
            centerOfCircle1.Y = pointOfRotation.Y + temp1Point.Y;
            centerOfCircle2.X = pointOfRotation.X + temp2Point.X;
            centerOfCircle2.Y = pointOfRotation.Y + temp2Point.Y;
            Invalidate();
        }
       

        void OnMouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {

                pointOfRotation.X = e.X;
                pointOfRotation.Y = e.Y;
            }
        }
    }
}
